void dump(decode_results *results) {
  if (results->decode_type == UNKNOWN) {
    Serial.print(F("Raw ("));
    Serial.print(results->rawlen, DEC);
    Serial.print(F(") "));
    for (int i = 0; i < results->rawlen; i++) {
      Serial.print(results->rawbuf[i], DEC);
      Serial.print(F(" "));
    }
    Serial.println("");
  } 
  else {
    if (results->decode_type == NEC) {
      Serial.print(F("NEC "));
    } 
    else if (results->decode_type == SONY) {
      Serial.print(F("SONY "));
    } 
    else if (results->decode_type == RC5) {
      Serial.print(F("RC5 "));
    } 
    else if (results->decode_type == RC6) {
      Serial.print(F("RC6 "));
    }
    else if (results->decode_type == PANASONIC) {
      Serial.print(F("PANASONIC "));
    }
    else {
      Serial.print(F("Unknown "));
    }
    
    if (results->value != 0) {
      Serial.print(results->value, HEX);
    } 
    else {
      for (int j=0; j<8; j++) {
        unsigned char x = results -> command[j];  //strip sign
        if (x < 16) {
          Serial.print(F("0"));  // leading zero
        }
        Serial.print(x, HEX);
        Serial.print(F(" "));
      }
    }
    Serial.print(F(" ("));
    Serial.print(results->bits, DEC);
    Serial.println(F(" bits)"));
  }
}

int find_ir_code (decode_results *results) {

  int rc;

  decode_results eeprom_ir_code;
  volatile unsigned int eeprom_ir_code_rawbuf[RAWBUF];
  eeprom_ir_code.rawbuf = &eeprom_ir_code_rawbuf[0];

  for (int action = 1; action <= 6; action++) {
    Serial.print(F("Matching to "));
    Serial.print(action);
    Serial.print(": ");

    read_ir_code_from_eeprom(action, &eeprom_ir_code);

    if (results -> decode_type == UNKNOWN) {
      rc = match_ir_code_raw(results, &eeprom_ir_code);
    } 
    else {
      if (eeprom_ir_code.value == 0) {
        rc = match_ir_code_long(results, &eeprom_ir_code);
      } 
      else {
        rc = match_ir_code_short(results, &eeprom_ir_code);
      }
    }

    if (rc == 1) {
      Serial.print(F("Match found\n"));
      return action;
    }
  }
  Serial.print(F("No match found\n"));
  return 0;
}

int match_ir_code_raw (decode_results *results, decode_results *eeprom_ir_code) {

  if (results -> rawlen != eeprom_ir_code -> rawlen) {
    Serial.print(F("Raw length mismatch\n"));
    return 0;
  }

  for (int j = 1; j < results -> rawlen; j++) {
    // ignore first interval, fuzzy match
    int diff = results -> rawbuf[j] - eeprom_ir_code -> rawbuf[j];
    diff = abs(diff);  // abs doesn't like expressions
    if (diff > IR_FUZZ) {
      Serial.print(F("Raw mismatch at byte: "));
      Serial.print(j);
      Serial.print(F(" stored: "));
      Serial.print(eeprom_ir_code -> rawbuf[j]);
      Serial.print(F(" input: "));
      Serial.print(results -> rawbuf[j]);
      Serial.print(F("\n"));
      return 0;
    }
  }
  Serial.print("Raw code matched\n");
  return 1;
}      

int match_ir_code_long (decode_results *results, decode_results *eeprom_ir_code) {
  if (results -> bits != eeprom_ir_code -> bits) {
    Serial.print(F("Bit length mismatch\n"));
    return 0;
  }

  for (int i=0; i<sizeof(results -> command); i++) {
    if (results -> command[i] != eeprom_ir_code -> command[i]) {
      Serial.print(F("Byte mismatch\n"));
      return 0;
    }
  }
  Serial.print(F("Long code matched\n"));
  return 1;
}      

int match_ir_code_short (decode_results *results, decode_results *eeprom_ir_code) {
  if (results -> value == eeprom_ir_code -> value) {
    Serial.print("Short code matched\n");
    return 1;
  } 
  else {
    Serial.print("Short code mismatch\n");
    return 0;
  }
}  

void emit_ir_code(decode_results *ir_code) {
  Serial.print(F("Emitting: "));
  dump(ir_code);
  switch (ir_code -> decode_type) {
  case NEC:
    irsend.sendNEC(ir_code -> value, ir_code -> bits);
    break;    
  case SONY:
    irsend.sendSony(ir_code -> value, ir_code -> bits);
    break;    
  case RC5:
    irsend.sendRC5(ir_code -> value, ir_code -> bits);
    break;    
  case RC6:
    irsend.sendRC6(ir_code -> value, ir_code -> bits);
    break;    
  case PANASONIC:
    irsend.sendPanasonic(ir_code -> command);
    break;    
  case UNKNOWN:
    irsend.enableIROut(38);
    // discard lead-in interval
    for (int i = 1; i < ir_code -> rawlen; i++) {
      if (i & 1) {
        irsend.space(ir_code -> rawbuf[i] * USECPERTICK);
      } 
      else {
        irsend.mark(ir_code -> rawbuf[i] * USECPERTICK);
      }
    }
    irsend.space(0); // Just to be sure
    break;
  default:  
    break;  
  } 
  irrecv.enableIRIn(); 
}




